% cm_allocate_at.m
% 在指定的地址 (requested_offset) 上分配内存。
% 这是验证器使用的函数，与分配器的 Best Fit 不同。
%
% @输入:
%   manager (struct): CacheManager 结构体。
%   size (numeric): 需要分配的大小。
%   buf_id (int): 要分配的 buffer ID。
%   requested_offset (numeric): 请求的起始地址。
% @输出:
%   manager (struct): 修改后的 CacheManager 结构体。
%   success (logical): 如果分配成功，则为 true。

function [manager, success] = cm_allocate_at(manager, size_needed, buf_id, requested_offset)
    
    success = false;
    
    if size_needed <= 0 || (requested_offset + size_needed) > manager.capacity
        return;
    end
    
    for i = 1:length(manager.free_blocks)
        fb = manager.free_blocks(i);
        % 检查请求的区域是否完全包含在当前空闲块中
        if requested_offset >= fb.start && (requested_offset + size_needed) <= (fb.start + fb.size)
            
            % 从 free_blocks 中移除当前块，稍后将切分后的剩余部分加回
            manager.free_blocks(i) = [];
            
            % 检查原始空闲块在分配后，前方是否留下碎片
            if fb.start < requested_offset
                prefix_frag = struct('start', fb.start, 'size', requested_offset - fb.start, 'buf_id', -1);
                manager.free_blocks = [manager.free_blocks; prefix_frag];
            end
            
            % 检查原始空闲块在分配后，后方是否留下碎片
            if (fb.start + fb.size) > (requested_offset + size_needed)
                suffix_frag = struct('start', requested_offset + size_needed, ...
                                     'size', (fb.start + fb.size) - (requested_offset + size_needed), ...
                                     'buf_id', -1);
                manager.free_blocks = [manager.free_blocks; suffix_frag];
            end
            
            % 添加新的已分配块
            new_alloc_block = struct('start', requested_offset, 'size', size_needed, 'buf_id', buf_id);
            manager.allocated_blocks = [manager.allocated_blocks; new_alloc_block];
            
            % 重新排序
            if ~isempty(manager.free_blocks)
                [~, sort_idx] = sort([manager.free_blocks.start]);
                manager.free_blocks = manager.free_blocks(sort_idx);
            end
            if ~isempty(manager.allocated_blocks)
                [~, sort_idx] = sort([manager.allocated_blocks.start]);
                manager.allocated_blocks = manager.allocated_blocks(sort_idx);
            end
            
            success = true;
            return;
        end
    end
end